package pers.whj.rpc.server;

import pers.whj.rpc.common.Config;
import pers.whj.rpc.common.ReflectionUtils;
import pers.whj.rpc.protocol.Request;
import pers.whj.rpc.protocol.Response;
import pers.whj.rpc.serialize.Decoder;
import pers.whj.rpc.serialize.DecoderImpl;
import pers.whj.rpc.serialize.Encoder;
import pers.whj.rpc.serialize.EncoderImpl;
import pers.whj.rpc.transport.RequestHandler;
import pers.whj.rpc.transport.TCPServer;
import pers.whj.rpc.transport.TCPThread;
import pers.whj.rpc.transport.TransportServer;

/**
 * rpc服务器端，可以注册服务，实现通信
 */
public class Server {
    private final TransportServer transportServer;
    private Encoder encoder;
    private Decoder decoder;
    private int port;
    /**
     * 处理请求接口的实现类
     */
    private RequestHandler handler = new RequestHandler() {
        @Override
        public byte[] onRequest(byte[] reqData) {
            Request request = decoder.decode(reqData, Request.class);
            //check the number of request
            if (transportServer instanceof TCPServer) {
                try {
                    TCPThread thread = ((TCPServer) transportServer).getThread(Thread.currentThread().getName());
                    if (request.getNumber() <= thread.getLastNumber()) {
                        return null;
                    } else {
                        thread.setLastNumber(request.getNumber());
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            Response response = new Response(request.getNumber());
            if (Config.DEBUG) {
                System.out.println("成功读取请求：" + request);
            }
            ServiceInstance serviceInstance = ServiceManager.getInstance().lookup(request);
            if (serviceInstance == null) {
                response.setCode(Response.CODE_ERROR);
                response.setErrorMsg("don't have this service!");
                if (Config.DEBUG) {
                    System.out.println("未查询到目标服务！");
                }
            } else {
                try {
                    Object result = ReflectionUtils.invoke(
                            serviceInstance.getObject(),
                            serviceInstance.getMethod(),
                            request.getParams()
                    );
                    response.setData(result);
                    if (Config.DEBUG) {
                        System.out.println("请求服务执行成功！");
                    }
                } catch (Exception e) {
                    response.setCode(Response.CODE_ERROR);
                    response.setErrorMsg(e.getMessage());
                    if (Config.DEBUG) {
                        e.printStackTrace();
                    }
                }
            }
            return encoder.encode(response);
        }
    };

    public Server() throws Exception {
        this.port = Config.SERVER_ADDRESS.getPort();
        this.transportServer = new TCPServer();
        this.encoder = new EncoderImpl();
        this.decoder = new DecoderImpl();
        this.transportServer.init(this.port, this.handler);
    }

    public int getPort() {
        return port;
    }

    public void setEncoder(Encoder encoder) {
        this.encoder = encoder;
    }

    public void setDecoder(Decoder decoder) {
        this.decoder = decoder;
    }

    public void setPort(int port) throws Exception {
        this.port = port;
        this.transportServer.init(this.port, this.handler);
    }

    public void setHandler(RequestHandler handler) throws Exception {
        this.handler = handler;
        this.transportServer.init(this.port, this.handler);
    }

    /**
     * 开启服务器
     *
     * @throws Exception 异常
     */
    public void start() throws Exception {
        this.transportServer.start();
    }

    /**
     * 停止服务
     */
    public void stop() {
        this.transportServer.stop();
    }

    /**
     * 注册，讲一个类注册为一个或多个服务实例
     * 注册了类中的所有public方法
     *
     * @param clazz 注册类类型
     * @param bean  注册类的实现
     * @param <T>   泛型
     */
    public <T> void register(Class<T> clazz, T bean) {
        ServiceManager.getInstance().register(clazz, bean);
    }
}
